summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2022-02-14 21:24:37 +0100
committerAnton Luka Šijanec <anton@sijanec.eu>2022-02-14 21:24:37 +0100
commitaaff3fb225290e639780bbdcd0a8d0f5c0121a50 (patch)
treec1c8b763a803706e6f27c89f4914046c13b4e8d4
parentgrem spat, ni testirano (diff)
downloaddiscord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.tar
discord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.tar.gz
discord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.tar.bz2
discord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.tar.lz
discord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.tar.xz
discord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.tar.zst
discord.c-aaff3fb225290e639780bbdcd0a8d0f5c0121a50.zip
-rw-r--r--.gitignore1
-rw-r--r--Makefile7
-rw-r--r--README.md2
-rw-r--r--src/api.c110
-rw-r--r--src/h.c58
-rw-r--r--src/main.c11
-rw-r--r--src/ui.c7
7 files changed, 152 insertions, 44 deletions
diff --git a/.gitignore b/.gitignore
index 20a965e..5ab9f09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
discord.c
# debugging log files
valgrind-out.txt
+.gdb_history
# files I like to keep in my WD
src.old/
src/ui.glade~
diff --git a/Makefile b/Makefile
index 8f2b580..b5615f1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
DESTDIR=/
SRCFILE=src/main.c
-CFLAGS += -Wextra -Wall -pedantic -g -O0 -Itmp -Isrc -I. -odiscord.c -Wno-unused-parameter -rdynamic -finput-charset=UTF-8 -fextended-identifiers
+O=0
+CFLAGS += -Wextra -Wall -pedantic -g -O$O -Itmp -Isrc -I. -odiscord.c -Wno-unused-parameter -rdynamic -finput-charset=UTF-8 -fextended-identifiers
LIBS += -lm
CFLAGS += $(shell pkg-config --cflags libwebsockets) $(shell pkg-config --cflags gtk+-3.0) $(shell pkg-config --cflags gmodule-export-2.0)
LIBS += $(shell pkg-config --libs libwebsockets) $(shell pkg-config --libs gtk+-3.0) $(shell pkg-config --libs gmodule-export-2.0)
@@ -19,9 +20,9 @@ default:
# tests if code compiles under gcc, clang and tcc
cc:
- make -e CC=gcc
make -e CC=tcc
- make -e CC=clang
+ make -e CC=gcc
+ scan-build make
install:
mkdir -p $(DESTDIR)/usr/bin/
diff --git a/README.md b/README.md
index 6c28aa0..91d681e 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,7 @@ it would be useful to have an android port, and luckily this is possible with li
* use an `i386` compatible machine with `debian` `bullseye` (I use a Dell Latitude D620)
* debugging with valgrind: `make valgrind-prepare` once and `make valgrind` for profiling `./discord.c`
* generating valgrind suppressions: `make gensupp`, running `make valgrind` afterwards will ignore all
-* `make cc` to compile code under `gcc`, `tcc` and `clang`
+* `make cc` to compile code under `tcc`, `gcc` and `clang` (with `scan-build`)
* optimization is always 0, binaries always have debug symbols
* `make -e CC=gcc` to choose a compiler instead of `cc`.
* `make -e CC="clang -fsanitize=address" && ASAN_OPTIONS=detect_leaks=1` to use `clang` leak checker
diff --git a/src/api.c b/src/api.c
index afbdfd8..cc91eff 100644
--- a/src/api.c
+++ b/src/api.c
@@ -25,6 +25,25 @@ void dc_api_stack (struct dc_api_io i) { /* stack output struct to be delivered
*(i.program->api_ios[i.program->api_ios_length++]) = i;
return;
}
+unsigned long long int dc_calculate_permissions (struct dc_user * u, struct dc_channel * c) {
+ unsigned long long int p = 0; /* note: this is NOT according to server's implementation of */
+ struct dc_role ** role = &c->guild->role; /* permission parsing, but should suffice for most */
+ while (*role) { /* cases. */
+ if ((*role)->status & DC_EVERYONE || dc_find_user((*role)->users, (*role)->users_length, u->id))
+ p |= (*role)->permissions;
+ role = &(*role)->next;
+ }
+ if (p & DC_ADMIN)
+ return DC_ALL_PERMISSIONS;
+ for (size_t i = 0; i < c->permissions_length; i++)
+ if (c->permissions[i]->user == u || dc_find_user(c->permissions[i]->role->users, c->permissions[i]->role->users_length, u->id) || c->permissions[i]->role->status & DC_EVERYONE) {
+ p &= ~c->permissions[i]->deny;
+ p |= c->permissions[i]->allow;
+ if ((*role)->permissions & DC_ADMIN)
+ return DC_ALL_PERMISSIONS;
+ }
+ return p;
+}
signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warnings of incompatible pointer times, we create a new type with enum later on */
enum dc_json_paths path = ctx->path_match-1; /* we assume that the order of incoming data is */
struct dc_lws_pass * pass = ctx->user; /* correct. op and t should come first, etc. */
@@ -32,7 +51,6 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
struct dc_program * program = pass->api_io.program;
pass->json_reason = reason;
if (reason == LEJPCB_FAILED || reason == LEJPCB_START || (reason == LEJPCB_COMPLETE && pass->packet != DC_MESSAGE_CREATE /* hack for lejp bug with wrong path on OBJECT_END */)) {
- if (reason == LEJPCB_COMPLETE)
DC_API_IO_GC(pass->api_io);
pass->packet = DC_NONE;
return '\0';
@@ -74,6 +92,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
DC_MR(program->users); /* don't need DC_IN_PROGRESS, we have ref in cl */
program->users[program->users_length++] = client->user = dc_user_init();
client->user->status |= DC_INCOMPLETE; /* when ->disc is set, it's complete */
+ client->user->program = program;
} /* we do not check on the object end */
switch (path) { /* email is already set from login */
case DC_JSON_ME_USERNAME:
@@ -96,6 +115,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
if ((path == DC_JSON_ME || path == DC_JSON_USER || path == DC_JSON_MESSAGE_AUTHOR || path == DC_JSON_MESSAGE_REFOBJ_AUTHOR || path == DC_JSON_MESSAGE_MENTION_USER || path == DC_JSON_MESSAGE_REFOBJ_MENTION_USER || path == DC_JSON_MEMBER) && reason == LEJPCB_OBJECT_START) {
/* dc_user_free(pass->api_io.user); */ /* parser branches MUST ALWAYS set to 0 */
pass->api_io.user = dc_user_init(); /* and possibly free api_io members after! */
+ pass->api_io.user->program = program;
pass->api_io.user->status |= DC_IN_PROGRESS; /* if we never get here again */
}
if ((path == DC_JSON_ME || path == DC_JSON_USER || path == DC_JSON_MESSAGE_AUTHOR || path == DC_JSON_MESSAGE_REFOBJ_AUTHOR || path == DC_JSON_MESSAGE_MENTION_USER || path == DC_JSON_MESSAGE_REFOBJ_MENTION_USER || path == DC_JSON_MEMBER) && reason == LEJPCB_OBJECT_END) {
@@ -158,7 +178,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
struct dc_channel * ch;
if ((ch = dc_find_channel(program->channels, program->channels_length, pass->api_io.channel->id)))
- DC_TRANSFER_CHANNEL(pass->api_io.channel, ch);
+ dc_transfer_channel(pass->api_io.channel, ch);
pass->api_io.channel = dc_addr_channel(program, DC_ISAE(program->channels), pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
if (!dc_find_ll_channel(client->guilds[0]->channel, pass->api_io.channel->id)) {
fprintf(stderr, "new DM id=%llu (:\n", pass->api_io.channel->id);
@@ -182,18 +202,15 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
channel = &(*channel)->next;
struct dc_channel * ch;
if ((ch = dc_find_channel(program->channels, program->channels_length, pass->api_io.channel->id)))
- DC_TRANSFER_CHANNEL(pass->api_io.channel, ch);
+ dc_transfer_channel(pass->api_io.channel, ch);
pass->api_io.channel = dc_addr_channel(program, DC_ISAE(program->channels), pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
if (!dc_find_ll_channel(gu->channel, pass->api_io.channel->id)) {
fprintf(stderr, "new channel id=%llu (:\n", pass->api_io.channel->id);
pass->api_io.channel->next = NULL;
*channel = pass->api_io.channel;
}
- struct dc_permission ** pe = &pass->api_io.channel->permission;
- while (*pe) { /* fix all permission pointers to channel to this new channel */
- (*pe)->channel = pass->api_io.channel;
- pe = &(*pe)->next;
- }
+ for (size_t i = 0; i < pass->api_io.channel->permissions_length; i++)
+ pass->api_io.channel->permissions[i]->channel = pass->api_io.channel;
switch (path) {
case DC_JSON_MESSAGE_MENTION_CHANNEL:
if (pass->api_io.message)
@@ -268,13 +285,14 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
if (path == DC_JSON_MEMBERSHIP && (reason == LEJPCB_OBJECT_END || reason == LEJPCB_OBJECT_START))
pass->api_io.id = 0;
- if (pass->packet == DC_MESSAGE_CREATE && reason == LEJPCB_COMPLETE) {
+ if (pass->packet == DC_MESSAGE_CREATE && path == DC_JSON_MESSAGE && reason == LEJPCB_OBJECT_START) {
pass->api_io.message = dc_message_init();
pass->api_io.message->reply = dc_message_init();
pass->api_io.message->reply->status |= DC_IN_PROGRESS;
pass->api_io.message->status |= DC_IN_PROGRESS;
}
- if (pass->packet == DC_MESSAGE_CREATE && pass->api_io.message && path == DC_JSON_MESSAGE && reason == LEJPCB_COMPLETE /* hack for lejp bug with wrong path on OBJECT_END */ ) {
+ if (pass->packet == DC_MESSAGE_CREATE && pass->api_io.message && reason == LEJPCB_COMPLETE) {
+ int ismessage = 0;
struct dc_message * me;
if (!pass->api_io.message->id || !pass->api_io.message->channel || !DC_MESSAGE_SUPPORTED(pass->api_io.message->type)) {
dc_message_free(pass->api_io.message, DC_UNSET);
@@ -285,6 +303,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
if (!pass->api_io.message->reply->id || !pass->api_io.message->reply->channel || !DC_MESSAGE_SUPPORTED(pass->api_io.message->reply->type)) {
dc_message_free(pass->api_io.message->reply, DC_UNSET);
pass->api_io.message->reply = NULL;
+ goto no_reply;
}
pass->api_io.message->reply->status &= ~DC_IN_PROGRESS;
pass->api_io.message->reply->time = DC_ID2TIME(pass->api_io.message->reply->id);
@@ -299,6 +318,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
if (!dc_find_ll_message(pass->api_io.message->reply->channel->message, pass->api_io.message->reply->id)) {
fprintf(stderr, "new message reply id=%llu (:\n", pass->api_io.message->reply->id);
+ ismessage++;
if (*message) {
pass->api_io.message->reply->next = (*message)->next;
(*message)->next = pass->api_io.message->reply;
@@ -308,6 +328,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
}
}
+no_reply:
pass->api_io.message->status &= ~DC_IN_PROGRESS;
pass->api_io.message->time = DC_ID2TIME(pass->api_io.message->id);
if ((me = dc_find_message(program->messages, program->messages_length, pass->api_io.message->id)))
@@ -321,6 +342,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
if (!dc_find_ll_message(pass->api_io.message->channel->message, pass->api_io.message->id)) {
fprintf(stderr, "new message id=%llu (:\n", pass->api_io.message->id);
+ ismessage++;
if (*message) {
pass->api_io.message->next = (*message)->next; /* based linked lists */
(*message)->next = pass->api_io.message;
@@ -329,7 +351,34 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
*message = pass->api_io.message;
}
}
+ struct dc_api_io tostack = {
+ .type = DC_API_MESSAGE,
+ .status = DC_OK,
+ .message = pass->api_io.message,
+ .program = program
+ };
+ if (ismessage)
+ dc_api_stack(tostack);
pass->api_io.message = NULL;
+ pass->packet = DC_NONE; /* we do this because this is triggered on LEJPCB_COMPLETE */
+ DC_API_IO_GC(pass->api_io); /* only as a hack due to a lejp bug */
+ return '\0';
+ }
+ if (path == DC_JSON_GUILD_CHANNEL_PERMISSION && reason == LEJPCB_OBJECT_START) {
+ pass->api_io.permission = dc_permission_init();
+ pass->api_io.permission->channel = pass->api_io.channel;
+ pass->api_io.permission->status = DC_IN_PROGRESS;
+ }
+ if (path == DC_JSON_GUILD_CHANNEL_PERMISSION && reason == LEJPCB_OBJECT_END) {
+ if (!pass->api_io.permission || (!pass->api_io.permission->user && !pass->api_io.permission->role) || (!pass->api_io.permission->user && !pass->api_io.permission->role)) {
+ dc_permission_free(pass->api_io.permission, DC_UNSET);
+ pass->api_io.permission = NULL;
+ return '\0';
+ }
+ pass->api_io.permission->status &= ~DC_IN_PROGRESS;
+ DC_MR(pass->api_io.channel->permissions);
+ pass->api_io.channel->permissions[pass->api_io.channel->permissions_length++] = pass->api_io.permission;
+ pass->api_io.permission = NULL;
}
if (reason & LEJP_FLAG_CB_IS_VALUE) {
struct dc_user * user; /* this is just a var for you use */
@@ -436,6 +485,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
if (!(user = dc_find_user(program->users, program->users_length, pass->api_io.id))) {
št |= 1;
user = dc_user_init();
+ user->program = program;
user->id = pass->api_io.id;
}
if (!(role = dc_find_role(program->roles, program->roles_length, id))) {
@@ -467,7 +517,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
case DC_JSON_MESSAGE_CONTENT:
if (pass->api_io.message) { /* lejp parses in chunks of 256, msg is 2k */
if (!pass->api_io.message->message) /* so we don't have garbag */
- pass->api_io.message->message = strdup("");
+ pass->api_io.message->message = strdup(ctx->buf);
pass->api_io.message->message = realloc(pass->api_io.message->message, strlen(pass->api_io.message->message)+strlen(ctx->buf)+1);
strcat(pass->api_io.message->message, ctx->buf);
}
@@ -501,10 +551,43 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
case DC_JSON_MESSAGE_REFOBJ_CONTENT:
if (pass->api_io.message && pass->api_io.message->reply) {
if (!pass->api_io.message->reply->message)
- pass->api_io.message->reply->message = strdup("");
+ pass->api_io.message->reply->message = strdup(ctx->buf);
pass->api_io.message->reply->message = realloc(pass->api_io.message->reply->message, strlen(pass->api_io.message->reply->message)+strlen(ctx->buf)+1);
strcat(pass->api_io.message->reply->message, ctx->buf);
}
+ break;
+ case DC_JSON_GUILD_CHANNEL_PERMISSION_TYPE:
+ if (pass->api_io.permission)
+ pass->api_io.permission->type = atoi(ctx->buf);
+ break;
+ case DC_JSON_GUILD_CHANNEL_PERMISSION_ID: /* we assume we get user before perm */
+ if (pass->api_io.permission) {
+ pass->api_io.permission->user = dc_find_user(program->users, program->users_length, strtoull(ctx->buf, NULL, 10));
+ pass->api_io.permission->role = dc_find_role(program->roles, program->roles_length, strtoull(ctx->buf, NULL, 10));
+ if (!pass->api_io.permission->role || !pass->api_io.permission->user)
+ switch (pass->api_io.permission->type) {
+ case DC_USER:
+ pass->api_io.permission->user = dc_user_init();
+ pass->api_io.permission->user->program = program;
+ pass->api_io.permission->user->id = strtoull(ctx->buf, NULL, 10);
+ dc_addr_user(program, DC_ISAE(program->users), pass->api_io.permission->user, DC_UNSET);
+ break;
+ case DC_ROLE:
+ pass->api_io.permission->role = dc_role_init();
+ pass->api_io.permission->role->id = strtoull(ctx->buf, NULL, 10);
+ dc_addr_role(program, DC_ISAE(program->roles), pass->api_io.permission->role, DC_UNSET);
+ break;
+ }
+ }
+ break;
+ case DC_JSON_GUILD_CHANNEL_PERMISSION_DENY:
+ if (pass->api_io.permission)
+ pass->api_io.permission->deny = strtoull(ctx->buf, NULL, 10);
+ break;
+ case DC_JSON_GUILD_CHANNEL_PERMISSION_ALLOW:
+ if (pass->api_io.permission)
+ pass->api_io.permission->allow = strtoull(ctx->buf, NULL, 10);
+ break;
default:
break;
}
@@ -689,8 +772,7 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
void dc_api_i (struct dc_api_io i) { /* this function does not call attached functions, only output does that */
struct lws_client_connect_info info;
struct dc_lws_pass * pass;
- if (!i.program)
- return;
+ assert(i.program);
if (i.program->lws_context && !(i.status & DC_FROM_LWS))
lws_service(i.program->lws_context, 0); /* DO NOT CALL THIS FROM _cb! */
switch (i.type) {
diff --git a/src/h.c b/src/h.c
index 81d7179..b08861e 100644
--- a/src/h.c
+++ b/src/h.c
@@ -62,27 +62,31 @@ enum dc_status { /* theese are flags and should be and-checked */
#define DC_VOICE_SPEAK (1 << 21)
#define DC_ALL_PERMISSIONS (DC_ADMIN | DC_CHANNEL_VIEW | DC_MESSAGE_SEND | DC_MESSAGE_READ | DC_VOICE_LISTEN | DC_VOICE_SPEAK) /* admins get this@parsing, UI need not check admin separatly */
enum dc_channel_type { /* other types exist, but are not implemented/understood */
- DC_GC = 0, /* guild channel */
- DC_DM = 1, /* direct messages channel */
- DC_VOICE = 2, /* all enum fields here have values same as the values that the server sends */
- DC_GROUP_DM = 3
+ DC_GC, /* guild channel */
+ DC_DM, /* direct messages channel */
+ DC_VOICE, /* all enum fields here have values same as the values that the server sends */
+ DC_GROUP_DM
};
#define DC_CHANNEL_SUPPORTED(x) (x == DC_GC || x == DC_DM || x == DC_VOICE || x == DC_GROUP_DM)
enum dc_ws_packet { /* op numbers of websocket packets or json objects in other words */
DC_PING = 1,
DC_STRPKTOFF = 100, /* here follow string types (t) */
DC_NONE = DC_STRPKTOFF + 0, /* unknown packet or packet type not yet defermined */
- DC_MESSAGE_CREATE = DC_STRPKTOFF + 1,
+ DC_MESSAGE_CREATE,
}; /* intents enum was removed - intents're for bots, clients have capabilities - are not understood */
char * dc_ws_packet[] = {
"",
"MESSAGE_CREATE"
};
enum dc_message_type { /* other types exist, but are not implemented/understood, same values as server */
- DC_MESSAGE = 0,
+ DC_MESSAGE,
DC_REPLY = 19,
};
#define DC_MESSAGE_SUPPORTED(x) (x == DC_MESSAGE || x == DC_REPLY)
+enum dc_permission_type { /* same values as server */
+ DC_ROLE,
+ DC_USER
+};
enum dc_api_io_type {
/* all output structs have important structs set when an output is broadcast, for example if we get a channel from server but we don't possess it's guild (by id), api will wait for the guild and hold the channel in it's cache. for messages, tags in message are also parsed and queried. roles in premissions in channels are also fetched but not users in permissions, because permissions are currently only used for checking our permissions, not others' */
/* none of the outputs transfer memory ownership. tr0 for inputs means transfer none, trp means pointer to struct owned by library is to be passed, tr1 means transfer of ownership to library */
@@ -423,7 +427,6 @@ struct dc_guild {
DC_STRUCT_PREFIX
char * name; /* yesfree */
unsigned long long int id; /* 0 for virtual DMs guild */
- struct dc_client * client; /* nofree */
struct dc_channel * channel; /* nofree - first channel */
struct dc_role * role; /* nofree - first role. NOTE: role->id == guild->id => @everyone role */
enum dc_status status; /* /\ if NULL then assume all permissions - a DM guild */
@@ -453,7 +456,6 @@ struct dc_client * dc_client_init () {
s->guilds_length = 1; /* because of duplicated 0 id value; freeing is therefore done from */
s->guilds[0] = dc_guild_init(); /* dc_client_free */
s->guilds[0]->name = strdup("Direct messages"); /* TODO: use gettext or similar for t9ns */
- s->guilds[0]->client = s;
return s;
}
void dc_client_free (struct dc_client * s, enum dc_status t) {
@@ -489,7 +491,7 @@ struct dc_channel {
struct dc_guild * guild; /* nofree */
struct dc_channel * next; /* nofree - next channel (linked list of all channel of dc_guild) */
struct dc_message * message; /* nofree - first message (ordered by time) */
- struct dc_permission * permission; /* nofree - first permission */
+ DC_ISASQ(permission); /* yesfree array and members - ch permissions for users/roles */
enum dc_status status;
DC_ISASQ(user); /* yesfree array only - participants in DM channels */
#ifdef DC_UI_GTK
@@ -500,14 +502,17 @@ struct dc_channel {
struct dc_channel * dc_channel_init () {
struct dc_channel * s = calloc(1, sizeof(*s));
DC_ISASIQ(user);
+ DC_ISASIQ(permission);
return s;
}
+void dc_permission_free (struct dc_permission *, enum dc_status);
void dc_channel_free (struct dc_channel * s, enum dc_status t) {
if (!s)
return;
free(s->name);
free(s->topic);
free(s->users);
+ DC_ISAF(permission);
if (!(t & DC_REPLACE))
free(s);
}
@@ -522,6 +527,7 @@ struct dc_message {
struct dc_message * reply; /* nofree - this message replies to another message or NULL */
enum dc_status status;
enum dc_message_type type;
+ struct dc_client * client; /* nofree - set when sending message to the client that should send */
DC_ISASQ(user); /* yesfree pointer array only - mentions */
DC_ISASQ(role); /* yesfree pointer array only - mentions */
DC_ISASQ(channel); /* yesfree pointer array only - mentions */
@@ -571,6 +577,7 @@ struct dc_user {
char * username; /* yesfree */
unsigned long long int id;
short int discriminator;
+ struct dc_program * program; /* nofree - for dc_calculate_permissions */
enum dc_status status;
};
struct dc_user * dc_user_init () {
@@ -588,10 +595,10 @@ struct dc_permission { /* permissions can be individual on a per-channel basis *
DC_STRUCT_PREFIX /* assume all permissions */
unsigned long long int allow;
unsigned long long int deny;
+ enum dc_permission_type type;
struct dc_channel * channel; /* nofree - on which channel does it apply */
struct dc_user * user; /* nofree - non-null if permission applies to a user */
struct dc_role * role; /* nofree - non-null if it applies to a role */
- struct dc_permission * next; /* nexrt permission in ll in channel */
enum dc_status status;
}; /* permissions are only useful for checking OUR permissions, not others'. keep that in mind. */
struct dc_permission * dc_permission_init () {
@@ -643,7 +650,6 @@ struct dc_program { /* data storage and token used for communication with the li
DC_ISASQ(message); /* yesfree */
DC_ISASQ(role); /* yesfree */
DC_ISASQ(user); /* yesfree */
- DC_ISASQ(permission); /* yesfree */
DC_ISASQ(attached_function); /* yesfree */
DC_ISASQ(api_io); /* yesfree */
struct lws_context * lws_context; /* yesfree */
@@ -691,13 +697,12 @@ struct dc_program * dc_program_init () {
DC_ISASIQ(message);
DC_ISASIQ(role);
DC_ISASIQ(user);
- DC_ISASIQ(permission);
DC_ISASIQ(attached_function);
DC_ISASIQ(api_io);
struct dc_api_io io; /* attach a function for pinging wss of every client */
memset(&io, 0, sizeof(io));
io.type = DC_API_ATTACH;
- io.attached_function = calloc(1, sizeof(struct dc_attached_function));
+ io.attached_function = dc_attached_function_init();
io.attached_function->type = DC_API_TIMEOUT;
io.attached_function->every = 0; /* repediately call, handle_ping handles timing */
io.attached_function->function = dc_handle_ping;
@@ -715,7 +720,6 @@ void dc_program_free (struct dc_program * s, enum dc_status t) {
DC_ISAF(message);
DC_ISAF(role);
DC_ISAF(user);
- DC_ISAF(permission);
DC_ISAF(attached_function);
DC_ISAF(api_io);
if (!(t & DC_REPLACE))
@@ -723,7 +727,6 @@ void dc_program_free (struct dc_program * s, enum dc_status t) {
}
void dc_api_stack (struct dc_api_io);
#define DC_FIND_X(x) struct dc_##x * dc_find_##x(struct dc_##x ** p, size_t l, unsigned long long int id) { \
- assert(id); \
for (size_t i = 0; i < l; i++) \
if (p[i]->id == id) { \
/* fprintf(stderr, "id %llu was found!\n", id); */ /* too much */ \
@@ -796,14 +799,23 @@ DC_GEN_X(message, MESSAGE)
DC_FIND_LL_X(message)
#define DC_ISAE(a) &(a), &(a##_sizeof), &(a##_length) /* ISA Expand */
#define DC_ISAN NULL, NULL, NULL /* ISA NULL */
-#define DC_TRANSFER_CHANNEL(n, o) do { /* n is going to DC_REPLACE o, transfer important data */ \
- (n)->message = (o)->message; /* don't transfer perms because we get them in the new */ \
- (n)->next = o->next; /* new channel object */ \
- DC_IF_UI_GTK( \
- memmove(&(n)->iter, &(o)->iter, sizeof(GtkTreeIter)); \
- (n)->is_iter = (o)->is_iter; \
- ) \
- } while(0)
+void dc_transfer_channel(struct dc_channel * n, struct dc_channel * o) { /* n is going to _REPLACE o */ \
+ n->message = o->message; /* don't transfer perms because we get them in the new */ \
+ n->next = o->next; /* new channel object */ \
+ DC_IF_UI_GTK(
+ memmove(&n->iter, &o->iter, sizeof(GtkTreeIter));
+ n->is_iter = o->is_iter;
+ )
+ if (!n->permissions_length) {
+ free(n->permissions);
+ n->permissions = o->permissions;
+ n->permissions_sizeof = o->permissions_sizeof;
+ n->permissions_length = o->permissions_length;
+ o->permissions = NULL;
+ o->permissions_sizeof = 0;
+ o->permissions_length = 0;
+ }
+}
#define DC_TRANSFER_GUILD(n, o) do { \
DC_IF_UI_GTK( \
memmove(&(n)->iter, &(o)->iter, sizeof(GtkTreeIter)); \
diff --git a/src/main.c b/src/main.c
index b202cdc..d658caa 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,6 +11,12 @@ void dc_signal (int i) {
dc_interrupted++;
return;
}
+enum dc_status dc_print_message (struct dc_api_io o, void * n) {
+ fprintf(stderr, "dc_print_message: %s#%s %s#%04d: %s\n", o.message->channel->guild->name,
+ o.message->channel->name, o.message->user->username,
+ o.message->user->discriminator, o.message->message);
+ return DC_OK;
+}
int main (int argc, char * argv[]) {
if (DC_JSON_PATHS_LENGTH != sizeof(dc_json_paths)/sizeof(dc_json_paths[0]) || DC_JSON_PATHS_LENGTH > 255) {
fprintf(stderr, "json paths enum: %d, array: %d (255 is max, must be same)\n", DC_JSON_PATHS_LENGTH, sizeof(dc_json_paths)/sizeof(dc_json_paths[0]));
@@ -28,6 +34,11 @@ int main (int argc, char * argv[]) {
};
dc_api_i(i);
signal(SIGINT, dc_signal);
+ i.type = DC_API_ATTACH;
+ i.attached_function = dc_attached_function_init();
+ i.attached_function->type = DC_API_MESSAGE;
+ i.attached_function->function = dc_print_message;
+ dc_api_i(i);
while (!dc_interrupted)
i = dc_api_o(i);
/* dc_ui(argc, argv); */
diff --git a/src/ui.c b/src/ui.c
index 279ef4f..d7feb7e 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -14,6 +14,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(gchar, g_free)
struct dc_ui_data {
GtkBuilder * b;
GKeyFile * k;
+ struct dc_client * c;
};
/*
# configuration file - loaded at startup, saved at exit, comments persist - description:
@@ -77,9 +78,9 @@ void dc_ui_spawn_channel (struct dc_channel * c /* needs a functional guild or s
GtkTreeIter i;
if (!c) {
gtk_tree_store_clear(l);
- for (size_t i = 0; i < c->guild->client->guilds_length; i++) {
- c->guild->client->guilds[i]->is_iter = FALSE;
- struct dc_channel * ch = c->guild->client->guilds[i]->channel;
+ for (size_t i = 0; i < d->c->guilds_length; i++) {
+ d->c->guilds[i]->is_iter = FALSE;
+ struct dc_channel * ch = d->c->guilds[i]->channel;
while (ch) {
ch->is_iter = FALSE;
ch = ch->next;